/******************************************
 * Nombre del archivo: At_Lista_Literal.java
 * Universidad del Valle de Guatemala
 * Curso: Algoritmos y Estructura de Datos
 * Autores:
 *      * Martín Guzmán     08041
 *      * David Hsieh       08225
 *      * Eduardo Mejicano  08058
 *      * Kevin Sánchez     08302
 * Fecha: 21 de agosto de 2009
 * Descripción:
*******************************************/
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner;

public class At_Lista_Literal extends Atomo{

    ArrayList<String> lista = new ArrayList<String>();
    At_Lista sub_lista;
    String texto_lista="";
    private static Scanner scan = new Scanner(System.in);
    
    /*****************************************
     * Método: At_Lista_Literal
     * Autor: David Hsieh
     * Uso: Constructor. Convierte una cadena
     *      en una lista
     * Retorno: Sin retorno. Contiene una lista
     *          a partir de una cadena.
     *****************************************/
    public At_Lista_Literal(String lista){
        texto_lista=lista;
        //texto_lista="'(1 2 (1 2))";//TEMPORAL!! QUITAR
        //System.out.println("DENTRO DE LISTA LITERAL\t"+texto_lista);//TODO quitar esto
        Arreglar_texto();
        //System.out.println("DENTRO DE LISTA LITERAL2\t"+texto_lista);//TODO quitar esto
        //System.out.println(""+lista);//TODO quitar esto
    }

    /*****************************************
     * Método: At_Lista_Literal
     * Autor: Martín Guzmán
     * Uso: Constructor. Para operar de una vez
     *      un comando como car o cdr.
     *      Convierte una cadena en una lista.
     * Retorno: Sin retorno. Contiene una lista
     *          a partir de una cadena.
     *****************************************/
    public At_Lista_Literal(String lista,boolean operar){
        if(operar==true){
            //System.out.println("lo que me mandaron a la lista listaral: ."+lista+".");//TODO quitar esto
            ArrayList<Integer> we = new ArrayList<Integer>();
            we.add(0);
            String texto=Operar(lista,we);
            texto_lista=texto;
            //System.out.println("termina iteraciones.."+this.texto_lista);//TODO quitar esto
            
        }
        else{
            lista=lista.replaceAll(" ",",");
            if(lista.startsWith("(")){
                lista=lista.substring(1,lista.length()-1);
            }
            texto_lista=lista;
            //System.out.println("DENTRO DE LISTA LITERAL"+texto_lista);//TODO quitar esto
            Arreglar_texto();
            //System.out.println("DENTRO DE LISTA LITERAL2"+texto_lista);//TODO quitar esto
            //System.out.println(""+lista);//TODO quitar esto
        }
    }

    /*****************************************
     * Método: getList
     * Autor: David Hsieh
     * Uso: Obtener la lista creada
     * Retorno: Lista creada.
     *****************************************/
    public ArrayList<String> getList(){
        return lista;
    }

    /*****************************************
     * Método: Operar
     * Autor: Martín Guzmán
     * Uso: Operar secuencias de CDR's
     * Retorno: String con el resultado de
     *          la secuencia respectivs.
     *****************************************/
    public String Operar(String operando,ArrayList<Integer> iteracion){

        //System.out.println("Operando que entra a operar: ."+operando+".");
        
        if(operando.startsWith("(,CAR") && operando.endsWith(",)")){
            
            //quita los paréntesis
            operando = operando.substring(1,operando.length()-1);
            //quita las comas
            operando = operando.substring(1,operando.length()-1);
            //quita la palabra CAR y la ,
            operando = operando.substring(4,operando.length());

            //System.out.println("FALTA ACOPLAR EL (CDR (CAR '(1 2 3))) **********");
            iteracion.add(1);
            return Operar(operando,iteracion);
        }
        if(operando.startsWith("(,CDR") && operando.endsWith(",)")){

            //quita los paréntesis
            operando = operando.substring(1,operando.length()-1);
            //quita las comas
            operando = operando.substring(1,operando.length()-1);
            //quita la palabra CAR y la ,
            operando = operando.substring(4,operando.length());

            //System.out.println("FALTA ACOPLAR EL (CDR (CDR '(1 2 3))) **********");
            iteracion.add(2);
            return Operar(operando,iteracion);
        }
        if(operando.startsWith("',(")){

            //System.out.println("texto lista adentro de '( "+operando);//TODO QUITAR ESTO
            texto_lista=operando;
            Arreglar_texto();

            //la varible iteración es una lista que puede tener un 1 si es un CAR o un 2 si es un CDR
            //cuando esta variable tenga un único elemento se termina el proceso de operación
            //y queda en this.lista la lista y en this.texto_lista el texto de dicha lista
            while(iteracion.size()>1){
                //System.out.println("Durante las iteraciones: ."+texto_lista+".");//TODO quitar esto
                //UN CDR
                if(iteracion.get(iteracion.size()-1).compareTo(2)==0){
                    //System.out.println("Operar un CDR...");
                    iteracion.remove(iteracion.size()-1);
                    texto_lista=(Op_Listas.Operar("CDR",this));
                    Arreglar_texto();
                }
                //UN CAR
                else if(iteracion.get(iteracion.size()-1).compareTo(1)==0){
                    //System.out.println("Operar un CAR...");
                    iteracion.remove(iteracion.size()-1);
                    texto_lista=(Op_Listas.Operar("CAR",this));
                    Arreglar_texto();
                }
            }
            return texto_lista;
        }
        if(operando.startsWith("(,READ")){

            //System.out.println("texto lista adentro de '( "+operando);//TODO QUITAR ESTO
            texto_lista=scan.nextLine();
            try{
                Arreglar_texto();
            }catch(Exception ex){
                System.out.println("Format input is incorrect");
            }
            

            //la varible iteración es una lista que puede tener un 1 si es un CAR o un 2 si es un CDR
            //cuando esta variable tenga un único elemento se termina el proceso de operación
            //y queda en this.lista la lista y en this.texto_lista el texto de dicha lista
            while(iteracion.size()>1){
                //System.out.println("Durante las iteraciones: ."+texto_lista+".");//TODO quitar esto
                //UN CDR
                if(iteracion.get(iteracion.size()-1).compareTo(2)==0){
                    //System.out.println("Operar un CDR...");
                    iteracion.remove(iteracion.size()-1);
                    texto_lista=(Op_Listas.Operar("CDR",this));
                    Arreglar_texto();
                }
                //UN CAR
                else if(iteracion.get(iteracion.size()-1).compareTo(1)==0){
                    //System.out.println("Operar un CAR...");
                    iteracion.remove(iteracion.size()-1);
                    texto_lista=(Op_Listas.Operar("CAR",this));
                    Arreglar_texto();
                }
            }
            return texto_lista;
        }
        if(operando.startsWith("(,LIST")){

            //System.out.println("texto lista adentro de (LIST) "+operando);//TODO QUITAR ESTO
            texto_lista=operando.replaceFirst(",LIST,",",");

            Arreglar_texto();
            //System.out.println("tamaño de la lista creada con LIST: "+this.lista.size());

            //la varible iteración es una lista que puede tener un 1 si es un CAR o un 2 si es un CDR
            //cuando esta variable tenga un único elemento se termina el proceso de operación
            //y queda en this.lista la lista y en this.texto_lista el texto de dicha lista
            while(iteracion.size()>1){
                //System.out.println("Durante las iteraciones: ."+texto_lista+".");//TODO quitar esto
                //UN CDR
                if(iteracion.get(iteracion.size()-1).compareTo(2)==0){
                    //System.out.println("Operar un CDR...");
                    iteracion.remove(iteracion.size()-1);
                    texto_lista=(Op_Listas.Operar("CDR",this));
                    Arreglar_texto();
                }
                //UN CAR
                else if(iteracion.get(iteracion.size()-1).compareTo(1)==0){
                    //System.out.println("Operar un CAR...");
                    iteracion.remove(iteracion.size()-1);
                    texto_lista=(Op_Listas.Operar("CAR",this));
                    Arreglar_texto();
                }
            }
            return texto_lista;
        }
        if(operando.startsWith("(,MAPCAR")){
            //System.out.println("Operando en mapcar: ."+operando.substring(2, operando.length()-2)+".");
            At_Lista lista_temporal = new At_Lista(operando.substring(2, operando.length()-2));
            //System.out.println("Operando en mapcar 2: ."+operando+".");
            texto_lista=lista_temporal.Obtener_valor();
            //System.out.println("Operando en mapcar 3: ."+operando+".");
            Arreglar_texto();
            //System.out.println("tamaño de la lista creada con MAPCAR: "+this.lista.size());

            //la varible iteración es una lista que puede tener un 1 si es un CAR o un 2 si es un CDR
            //cuando esta variable tenga un único elemento se termina el proceso de operación
            //y queda en this.lista la lista y en this.texto_lista el texto de dicha lista
            while(iteracion.size()>1){
                //System.out.println("Durante las iteraciones: ."+texto_lista+".");//TODO quitar esto
                //UN CDR
                if(iteracion.get(iteracion.size()-1).compareTo(2)==0){
                    //System.out.println("Operar un CDR...");
                    iteracion.remove(iteracion.size()-1);
                    texto_lista=(Op_Listas.Operar("CDR",this));
                    Arreglar_texto();
                }
                //UN CAR
                else if(iteracion.get(iteracion.size()-1).compareTo(1)==0){
                    //System.out.println("Operar un CAR...");
                    iteracion.remove(iteracion.size()-1);
                    texto_lista=(Op_Listas.Operar("CAR",this));
                    Arreglar_texto();
                }
            }
            return texto_lista;
        }
        else{
            //quita las comas
            //operando = operando.substring(1,operando.length()-1);
            //devuelve null si no está entre las variables
            //System.out.println("valor de variable supuesto: "+operando);
            texto_lista=Lista_Variables.getValor(operando);
            if (texto_lista == null){
                System.out.println("Sorry, there is no variable with this name");
                return "Error";
            }
            try{
                Arreglar_texto();
                while(iteracion.size()>1){
                    //System.out.println("Durante las iteraciones: ."+texto_lista+".");//TODO quitar esto
                    //UN CDR
                    if(iteracion.get(iteracion.size()-1).compareTo(2)==0){
                        //System.out.println("Operar un CDR...");
                        iteracion.remove(iteracion.size()-1);
                        texto_lista=(Op_Listas.Operar("CDR",this));
                        Arreglar_texto();
                    }
                    //UN CAR
                    else if(iteracion.get(iteracion.size()-1).compareTo(1)==0){
                        //System.out.println("Operar un CAR...");
                        iteracion.remove(iteracion.size()-1);
                        texto_lista=(Op_Listas.Operar("CAR",this));
                        Arreglar_texto();
                    }
                }
            }
            catch(Exception exp){
                System.out.println("Sorry, the variable you're referencing is not a list");
                return "Error";
            }
            return texto_lista;
        }
    }

    public String Obtener_valor(){
        return texto_lista;
    }


    /*****************************************
     * Método: Arreglar_texto
     * Autor: Martín Guzmán
     * Uso: divide en átomos el texto
     * Retorno: guarda los átomos en una lista.
     *****************************************/
    public ArrayList<String> Arreglar_texto(){
        texto_lista=texto_lista.replaceAll(" ", ",");
        
        if(texto_lista.startsWith("',")){
            texto_lista=texto_lista.substring(3,texto_lista.length()-1);
        }
        else if(texto_lista.startsWith("'")){
            texto_lista=texto_lista.substring(2,texto_lista.length()-1);
        }
        else if(texto_lista.startsWith("(,")){
            texto_lista=texto_lista.substring(1,texto_lista.length()-1);
        }
        else{
            texto_lista=texto_lista.substring(1,texto_lista.length()-1);
        }
        //System.out.println("texto_lista:::  "+texto_lista);

        String[] temporal=texto_lista.split(",");

        //pasar a una lista el arreglo de strings
        ArrayList<String> temporal_lista = new ArrayList<String>();
        for(int i=0;i<temporal.length;i++)
        {
            temporal_lista.add(temporal[i]);
        }
        //***********************************
        ArrayList<String> temporal_a_agregar = new ArrayList<String>();
        for(int i=0;i<temporal_lista.size();i++)
        {
            String sub_cadena=temporal_lista.get(i);
            if (temporal_lista.get(i).startsWith("("))//agrupar hasta que se cierre este paréntesis
            {
                int parentesis=1;
                int posicion=i;
                for(int j=i+1;j<temporal_lista.size();j++){
                    if(temporal[j].contains(")"))
                        parentesis--;
                    if (parentesis==0){
                        posicion=j;
                        break;
                    }
                    if(temporal[j].startsWith("("))
                        parentesis++;

                }
                sub_cadena="";
                //System.out.println("i"+i+" j:"+posicion);//TODO quitar esto
                for(int a=i;a<=posicion;a++){
                   sub_cadena+=","+temporal_lista.get(a);
                }
                sub_cadena=sub_cadena.substring(1, sub_cadena.length());//para quitarle la última ","
                i=posicion;
            }
            //System.out.println("Sub-cadena: ."+sub_cadena+".");//TODO quitar esto
            temporal_a_agregar.add(sub_cadena);
        }
        //quitar las cadenas vacías
        for(int i=0;i<temporal_a_agregar.size();i++)
        {
            if(temporal_a_agregar.get(i).isEmpty()){
                //System.out.println("removió 1");
                temporal_a_agregar.remove(i--);
            }
        }


        //poner el texto de la lista
        texto_lista="";
        lista.clear();
        for(int i=0;i<temporal_a_agregar.size();i++)
        {
            String temp = temporal_a_agregar.get(i);
            //ciclo para borrar los (, y ,)
            for(int j=0;j<temp.length();j++)
            {
                try{
                    if(temp.charAt(j)=='(' && temp.charAt(j+1)==',')
                    {
                        temp=temp.substring(0,j+1)+""+temp.substring(j+2, temp.length());
                        //j--;
                    }
                    if(temp.charAt(j)==')' && temp.charAt(j-1)==',')
                    {
                        temp=temp.substring(0,j-1)+""+temp.substring(j, temp.length());
                    }
                }catch(Exception ex){
                    System.out.println("error");
                }
            }
            //ciclo para quitar las "," y sustituirlos por " "
            for(int j=0;j<temp.length();j++)
            {
                try{
                    if(temp.charAt(j)==',')
                    {
                        temp=temp.substring(0,j)+" "+temp.substring(j+1, temp.length());
                    }
                }catch(Exception ex){
                    System.out.println("error");
                }
            }
            lista.add(temp);
            //System.out.println("Lo que se está agregando a la lista: ."+temp+".");
            texto_lista+=temp+" ";
        }
        texto_lista="("+texto_lista.substring(0,texto_lista.length()-1)+")";

        return temporal_a_agregar;
    }

}
